package com.atguigu.gmall.activity.receiver;

import com.atguigu.gmall.activity.mapper.SeckillGoodsMapper;
import com.atguigu.gmall.activity.service.SeckillGoodsService;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.activity.UserRecode;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.rabbitmq.client.Channel;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Fxz
 * @version 1.0
 * @date 2022-02-25 13:45
 */
@SuppressWarnings("all")
@Slf4j
@Component
@RequiredArgsConstructor
public class SeckillReceiver {

	private final SeckillGoodsMapper seckillGoodsMapper;

	private final RedisTemplate redisTemplate;

	private final SeckillGoodsService seckillGoodsService;

	/**
	 * 监听定时任务发送过来的消息，将秒杀商品放入缓存
	 */
	@SneakyThrows
	@RabbitListener(bindings = @QueueBinding(
			value = @Queue(value = MqConst.QUEUE_TASK_1, durable = "true", autoDelete = "false"),
			exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK), key = { MqConst.ROUTING_TASK_1 }))
	public void importRedis(Message message, Channel channel) {
		log.info("到点了,将今天的秒杀数据写入缓存...");

		// 查询当天的秒杀商品数据
		List<SeckillGoods> seckillGoods = seckillGoodsMapper.selectList(
				Wrappers.<SeckillGoods>lambdaQuery().eq(SeckillGoods::getStatus, 1).gt(SeckillGoods::getStockCount, 0)
						.apply("date_format(start_time,'%Y-%m-%d') = '" + DateUtil.formatDate(new Date()) + "'"));
		// 判断是否为空
		if (ObjectUtils.isNotEmpty(seckillGoods)) {
			// 过滤出缓存中不存在的秒杀商品
			List<SeckillGoods> goodsList = seckillGoods.stream().filter(
					item -> !redisTemplate.opsForHash().hasKey(RedisConst.SECKILL_GOODS, item.getSkuId().toString()))
					.collect(Collectors.toList());

			log.info("写入缓存的数据一共有:{}条", goodsList.size());

			// key:skuId value:Good
			Map<String, SeckillGoods> map = goodsList.stream()
					.collect(Collectors.toMap(item -> String.valueOf(item.getSkuId()), item -> item));
			// 将商品写入缓存
			redisTemplate.opsForHash().putAll(RedisConst.SECKILL_GOODS, map);
			// 为了防止超卖,将num的值存起来
			goodsList.forEach(item -> {
				redisTemplate.opsForValue().set(RedisConst.SECKILL_STOCK_PREFIX + item.getSkuId(),
						item.getStockCount());
				redisTemplate.convertAndSend("seckillpush", item.getSkuId() + ":" + 1);
			});

		}
		// 确认消息
		channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
	}

	@SneakyThrows
	@RabbitListener(bindings = @QueueBinding(
			value = @Queue(value = MqConst.QUEUE_SECKILL_USER, durable = "true", autoDelete = "false"),
			exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_USER), key = { MqConst.ROUTING_SECKILL_USER }))
	public void seckill(UserRecode userRecode, Message message, Channel channel) {
		if (ObjectUtils.isNotEmpty(userRecode)) {
			seckillGoodsService.seckillOrder(userRecode.getSkuId(), userRecode.getUserId());
		}
		channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
	}

	@SneakyThrows
	@RabbitListener(bindings = @QueueBinding(
			value = @Queue(value = MqConst.QUEUE_TASK_18, durable = "true", autoDelete = "false"),
			exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK), key = { MqConst.ROUTING_TASK_18 }))
	public void clearRedis(Message message, Channel channel) {
		// 查询秒杀结束的商品
		List<SeckillGoods> goodsList = seckillGoodsMapper.selectList(Wrappers.<SeckillGoods>lambdaUpdate()
				.eq(SeckillGoods::getStatus, 1).le(SeckillGoods::getEndTime, new Date()));
		// 删除缓存中对应的数据
		if (CollectionUtils.isNotEmpty(goodsList)) {
			goodsList.forEach(
					item -> redisTemplate.delete(RedisConst.SECKILL_STOCK_PREFIX + item.getSkuId().toString()));
		}
		redisTemplate.delete(RedisConst.SECKILL_GOODS);
		redisTemplate.delete(RedisConst.SECKILL_ORDERS);
		redisTemplate.delete(RedisConst.SECKILL_ORDERS_USERS);

		SeckillGoods goods = new SeckillGoods();
		goods.setStatus("2");
		seckillGoodsMapper.update(goods, Wrappers.<SeckillGoods>lambdaUpdate().eq(SeckillGoods::getStatus, 1)
				.le(SeckillGoods::getEndTime, new Date()));

		channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
	}

}
